Lab 4 - Zastosowanie ROS’a w robotyce

Modelowanie i sterowanie robotów - laboratorium

Lab 4 - Zastosowanie ROS’a w robotyce

Politechnika Poznańska

Instytut Robotyki i Inteligencji Maszynowej

Logo PP

Jakub Chudziński, Bartłomiej Kulecki


Instalacja potrzebnego oprogramowania

Na zajęciach będziemy pracować z ROS Jazzy Jalisco (bazującym na Ubuntu 24.04). Rekomendowane jest skorzystanie z dostarczonego i skonfigurowanego oprogramowania tworzącego tzw. kontener (Docker container). Instalacja jest opisana zarówno dla użytkowników Windowsa jak i Ubuntu. Na komputerach w laboratorium można pominąć proces instalacji i przejść do sekcji “Uruchomienie ROS’a”.

Ubuntu Logo ubuntu
  1.   Pobierz Docker Engine, instrukcja: https://docs.docker.com/engine/install/ubuntu/#install-using-the-repository
  2.   Opcjonalnie, możesz wykonać kroki poinstalacyjne dla Docker Engine przedstawione na stronie:
      https://docs.docker.com/engine/install/linux-postinstall/
  3.   Pobierz i zainstaluj Visual Studio Code poleceniem w Terminalu:   sudo apt-get install code
  4.   Otwórz VS Code i zainstaluj rozszerzenie (skrót CTRL+SHIFT+X) o nazwie “Remote Development”
Windows Logo win
  1.   Pobierz XLaunch Server ze strony https://sourceforge.net/projects/vcxsrv/ i zainstaluj.
  2.   Pobierz Docker Desktop ze strony https://docs.docker.com/desktop/install/windows-install/ i zainstaluj.
  3.   Pobierz Visual Studio Code ze strony https://code.visualstudio.com/download i zainstaluj.
  4.   Otwórz VS Code i zainstaluj rozszerzenie (skrót CTRL+SHIFT+X) o nazwie “Remote Development”.
  5.   Pobierz repozytorium:
  1.   jako zip i rozpakuj w wybranej lokalizacji na dysku jako ros2_ws_misr
  2.   LUB w wierszu polecenia za pomocą komendy:
    git clone -b jazzy-Windows https://github.com/LRMPUT/ros2_ws_misr.git

Uruchomienie ROS’a (Docker)

Ubuntu (lab) Logo ubuntu
  1.   Otwórz Terminal i uruchom Docker Engine poleceniem sudo systemctl start docker (może nie być konieczne).

  2.   W Terminalu uruchom polecenie:

    cd ~ && test -d ros2_ws_misr || git clone -b jazzy https://github.com/LRMPUT/ros2_ws_misr.git ; xhost + ; code ros2_ws_misr
  3.   W VS Code:

    • naciśnij przycisk widoczny w powiadomieniu w prawym dolnym rogu Reopen in Container
    • LUB naciśnij F1 i wpisz “Reopen in…”, wybierz "Dev Containers: Rebuild and Reopen in Container", i kliknij Enter
  4.   Poczekaj na pobranie i instalację potrzebnego oprogramowania.

Windows Logo win
  1.   Uruchom XLaunch Server z domyślnymi ustawieniami.
  2.   Uruchom Docker Desktop (pozostawiając w tle).
  3.   Uruchom VS Code i otwórz folder ros2_ws_misr.
  4.   W VS Code:
    • naciśnij przycisk widoczny w powiadomieniu w prawym dolnym rogu Reopen in Container
    • LUB naciśnij F1 i wpisz “Reopen in…”, wybierz "Dev Containers: Rebuild and Reopen in Container", i kliknij Enter
  5.   Poczekaj na pobranie i instalację potrzebnego oprogramowania.
Dla chętnych: instalacja i uruchomienie na Ubuntu bez Dockera

Instalacja bez Dockera na systemie Ubuntu 24.04

Oprócz rekomendowanej instalacji oprogramowania z wykorzystaniem Dockera, można również zastosować podejście, w którym instaluje się system operacyjny Ubuntu równolegle (obok) systemu Windows. Wówczas przy uruchamianiu komputera pojawia się możliwość wyboru systemu, który chcemy włączyć.
UWAGA! Zachowaj szczególną ostrożność przy instalacji Ubuntu na dysku twardym, zapoznaj się dokładnie z dostępnymi w sieci instrukcjami instalacji, tak aby nie usunąć przez przypadek Windowsa, jeśli tego nie chcesz.

Instrukcja instalacji ROS 2 Jazzy, tworzenia workspace i konfiguracji pod zajęcia znajduje się tutaj.

Wprowadzenie do ROS’a

Robot Operating System (ROS) to open-source’owe środowisko do tworzenia aplikacji dla robotów i systemów zrobotyzowanych. Dostarcza narzędzia do komunikacji między procesami, obsługi urządzeń (kamery, czujniki, sterowniki), modelowania oraz sterowania robotami. Jego architektura jest modułowa i rozproszona (SOA), co pozwala budować system z niezależnych komponentów, które można łatwo przenosić między projektami.

Programowanie w ROS najczęściej odbywa się w C++ lub Pythonie. C++ wykorzystywany jest zwykle w modułach wymagających wysokiej wydajności (np. sterowanie), natomiast Python sprawdza się przy szybkim prototypowaniu i przetwarzaniu danych, np. z kamer. Dużą zaletą ROS jest bogaty ekosystem gotowych pakietów tworzonych przez społeczność.

Środowisko ROS jest ściśle związane z systemami Linux (najczęściej Ubuntu). Znajomość terminala oraz języka angielskiego jest w praktyce niezbędna do pracy z dokumentacją i rozwiązywania problemów.

Istotnym elementem pracy w ROS jest możliwość równoległego korzystania z symulacji i realnego sprzętu. To samo oprogramowanie może działać zarówno w środowisku symulacyjnym, jak i na fizycznym robocie, co znacząco przyspiesza rozwój i testowanie systemu.

ROS (a obecnie szczególnie ROS 2) jest wykorzystywany nie tylko w edukacji i badaniach, ale również w zastosowaniach przemysłowych, m.in. w ramach inicjatywy ROS-Industrial.


Struktura funkcjonalna ROS’a

Robot Operating System jest zainstalowany w systemie (natywnie lub wewnątrz kontenera) pod ścieżką /opt/ros/jazzy lub w przypadku innych dystrybucji ROS’a: /opt/ros/<ROS-DISTRO>.
⚠️ ⚠️ ⚠️ Otwierając nowy terminal należy zawsze przed rozpoczęciem pracy wykonać komendę:
⚠️ ⚠️ ⚠️ source /opt/ros/jazzy/setup.bash
Komenda ta wskazuje potomnym procesom, gdzie jest zainstalowany ROS, ustawia wymagane zmienne środowiskowe - po prostu umożliwia korzystanie z ROS’a.

ROS ma architekturę modułową. Poszczególne węzły (które można interpretować jako procesy w systemie odpowiedzialne za różne zadania) komunikują się ze sobą korzystając ze standardowych dla ROSa sposobów takich jak topic i service.

ros-graph

Moduł (ang. module, package)

Moduł to zbiór procesów realizujących określone zadanie. Na moduł może składać się jeden lub więcej węzłów (ang. node). Przykładowym modułem może być aplikacja do przetwarzania danych biomedycznych, w której jeden z węzłów odpowiada za odbiór danych z różnych czujników, a drugi za przetwarzanie ich na komendy sterujące robotem.

Aby uruchomić pojedyczny węzeł z danego modułu wykorzystujemy komendę:

ros2 run [package_name] [node_name]

🛠️ Zadanie 1.1: Wykonaj poniższe polecenie, aby uruchomić przykładowy, domyślnie zainstalowany węzeł:

ros2 run turtlesim turtlesim_node

turtlesim

Węzeł (ang. node)

Proces pełniący określone zadanie. W obrębie modułu może być utworzone wiele współpracujących węzłów.

🛠️ Zadanie 1.2: Otwórz nowe okno terminala (CTRL+SHIFT+`), zainicjalizuj w nim ROS’a (komenda source /opt/ros/jazzy/setup.bash) i wyświetl listę aktywnych węzłów poleceniem:

ros2 node list

Jeśli w terminalu jest uruchomiony proces, który blokuje to okno i chcemy go zakończyć, należy użyć skrótu CTRL+C

Temat (ang. topic)

Węzły mogą się komunikować za pomocą tematów. Jeden z węzłów jest nazywany publikującym (ang. publisher lub advertiser), a drugi subskrybującym (ang. subscriber). Węzeł publikujący przesyła wiadomości na danym temacie i mogą być one odbierane przez wielu subskrybentów.

Jeśli węzeł turtlesim_node jest wyłączony, uruchom go.

🛠️ Zadanie 1.3: W nowym oknie terminala uruchom kolejny węzeł poleceniem:

ros2 run turtlesim turtle_teleop_key

Ten węzeł dodaje możliwość sterowania symulowanym żółwiem za pomocą strzałek klawiatury. Aby sterować żółwiem, kliknij najpierw na okno terminala z tym węzłem.

🛠️ Zadanie 1.4: W nowym oknie terminala wyświetl listę dostępnych tematów poleceniem:

ros2 topic list

🛠️ Zadanie 1.5: Wyświetl dane publikowane na temacie /turtle1/cmd_vel poniższym poleceniem. Poruszaj żółwiem i zaobserwuj publikowane dane.

ros2 topic echo /turtle1/cmd_vel

Wiadomość (ang. message)

Węzły przekazują pomiędzy sobą wiadomości, mogą to być np. przetworzone dane z czujnika.

🛠️ Zadanie 1.6: Wyświetl typ danych publikowanych na temacie /turtle1/cmd_vel.

ros2 topic type /turtle1/cmd_vel

🛠️ Zadanie 1.7: Aby wyświetlić informację o typie tej wiadomości, wykonaj polecenie:

ros2 interface show geometry_msgs/msg/Twist

Zazwyczaj wiadomości publikujemy wewnątrz zaprogramowanego węzła, ale istnieje również możliwość publikowania wiadomości z poziomu okna terminala:

ros2 topic pub [topic_name] [msg_type] [args]

🛠️ Zadanie 1.8: Wykonaj poniższe polecenie, aby wysterować symulowanego źółwia:

ros2 topic pub -1 /turtle1/cmd_vel geometry_msgs/msg/Twist 'linear:
  x: 2.0
  y: 0.0
  z: 0.0
angular:
  x: 0.0
  y: 0.0
  z: 1.0
'

Możesz jednocześnie publikować dane z wielu okien lub wielu węzłów. Spróbuj publikować powyższą komendę i jednocześnie sterować źółwiem za pomocą klawiatury.

Bibliotekami, które implementują powyższe funkcjonalności są rclpy dla Pythona oraz rclcpp dla C++, umożliwiają one np. tworzenie węzłów, czy dodawanie subskrybentów/publikujących.

Nauka ROS’a - tutoriale 🐢

Bardzo dobrym sposobem aby poznać ROS 2 są tutoriale z oficjalnej dokumentacji ROS’a. Podstawy są zaprezentowane na bazie prostego narzędzia jakim jest turtlesim.

Przykłady projektów w ROS’ie 🔥

Poniżej przedstawiono wybrane, popularne pakiety i zastosowania ROS 2, które pokazują, jak szerokie możliwości daje ten ekosystem – od robotów mobilnych, przez manipulatory, po symulację i wizję komputerową.

Moduł Przeznaczenie Opis
MoveIt 2 Planowanie ruchu Framework do planowania trajektorii dla manipulatorów i robotów mobilnych (kinematyka, kolizje, planowanie ścieżek).
Navigation2 Nawigacja robotów mobilnych Stos do autonomicznej nawigacji (mapowanie, lokalizacja, planowanie trasy, omijanie przeszkód).
Gazebo / Ignition Gazebo Symulacja robotów Zaawansowane środowisko symulacyjne do testowania robotów bez dostępu do sprzętu.
OpenCV + pakiety ROS 2 Wizja komputerowa Przetwarzanie obrazu z kamer: detekcja obiektów, śledzenie, rozpoznawanie.
RViz2 Wizualizacja danych Narzędzie do wizualizacji czujników, trajektorii, map i modeli robotów w 3D.
tf2 Transformacje układów współrzędnych Zarządzanie relacjami przestrzennymi między układami odniesienia (np. kamera–robot–świat).
micro-ROS Integracja z mikrokontrolerami Umożliwia uruchamianie ROS 2 na systemach wbudowanych (np. STM32, ESP32).
Universal Robots ROS2 Driver Sterowanie manipulatorami Integracja przemysłowych robotów z ROS 2 (planowanie ruchu, sterowanie, diagnostyka).

Tworzenie własnych programów w ROS’ie 🤖

Podstawową jednostką oprogramowania obejmującą kod źródłowy, pliki systemu kompilacji, dokumentację, testy i inne powiązane zasoby jest paczka/pakiet (ang. package). Może zawierać jeden lub wiele węzłów, bibliotek lub zasobów. Paczki w ROS’ie mogą być zainstalowane w różnych obszarach roboczych (ang. workspace):

W głównym obszarze roboczym znajdują się prekompilowane, oficjalne pakiety binarne dostarczane przez Open Robotics dla wybranej dystrybucji ROS 2 (np. Humble, Jazzy) instalowane za pomocą narzędzia apt. Jeśli chcemy utworzyć własną paczkę lub pobrać paczkę innego autora np. z GitHub’a, to ich miejsce docelowe to lokalny workspace.

Zazwyczaj lokalny workspace to katalog ~/ros2_ws (jednak nazwa i lokalizacja nie ma znaczenia). Ma on określoną strukturę podkatalogów:

🛠️ Zadanie 2.0: Uruchom terminal i przejdź do katalogu ~/ros2_ws, zapoznaj się z jego strukturą. Jest to Twoje środowisko pracy z ROS’em. Wyświetl jego zawartość korzystając z komendy ls, następnie przejdź do folderu (komenda cd) src i ponownie wyświetl zawartość tego katalogu. Jak nazywają się paczki zainstalowane w Twoim środowisku? Uwaga, wpisując nazwę docelowego folderu warto wykorzystywać auto-uzupełnianie nazw po wciśnięciu klawisza TAB.

🛠️ Zadanie 2.1: Utwórz własną paczkę. Przejdź do katalogu ~/ros2_ws, ustaw zmienne środowiskowe komendą source /opt/ros/jazzy/setup.bash. Następnie przejdź do katalogu src i utwórz paczkę o własnej nazwie (imię i nazwisko / inicjały), np. jank_pkg:

cd ~/ros2_ws/src
ros2 pkg create --build-type ament_python --license Apache-2.0 --node-name dist_node jank_pkg

Komenda ta tworzy paczkę dedykowaną do aplikacji w języku Python. Podając argument --node-name automatycznie utworzony został plik dist_node.py i dodany został węzeł dist_node.

🛠️ Zadanie 2.2: Zbuduj paczkę. W tym celu wykorzystać należy colcon - narzędzie ROS 2 do automatycznego budowania (kompilacji) paczek. Wykonaj poniższe komendy:

cd ~/ros2_ws
colcon build --symlink-install

🛠️ Zadanie 2.3: Uruchom node za pomocą komendy:

ros2 run [package_name] dist_node

W wyniku tej komendy powinien pojawić się tylko komunikat Hi from [package_name]., ponieważ tylko to jest zaimplementowane w utworzonym skrypcie.

🛠️ Zadanie 2.4: Edytuj skrypt src/package_name/package_name/dist_node.py. Wklej poniższy kod i zapoznaj się z nim.

import rclpy
from rclpy.node import Node
from turtlesim.msg import Pose
from std_msgs.msg import Float32

class TurtleTracker(Node):
    def __init__(self):
        super().__init__('dist_node')
        # Initialize variables to keep track of the previous pose and total distance traveled
        self.prev_pose = None
        self.total_distance = 0.0
        self.dist_msg = Float32()
        
        # Create a subscription to the /turtle1/pose topic to receive pose updates
        self.subscription = self.create_subscription(
            Pose, '/turtle1/pose', self.pose_listener_callback, 10)
        self.subscription  # prevent unused variable warning
        
        # Create a publisher to publish the total distance traveled on the 'travelled_distance' topic
        self.distance_publisher = self.create_publisher(Float32, 'travelled_distance', 10)
        # Create a timer to periodically publish the total distance traveled
        self.timer = self.create_timer(timer_period_sec=0.2, callback=self.timer_callback)

    # Callback function to handle incoming pose messages
    def pose_listener_callback(self, pose_msg):
        self.get_logger().info('I got new pose: x=%f, y=%f, theta=%f' % (pose_msg.x, pose_msg.y, pose_msg.theta))
        if self.prev_pose is not None:
            # Calculate the distance traveled since the last pose update and add it to the total distance
            pass   
        self.prev_pose = pose_msg
        
    # Callback function to publish the total distance traveled at regular intervals
    def timer_callback(self):
        self.dist_msg.data = float(self.total_distance)
        self.distance_publisher.publish(self.dist_msg)
        self.get_logger().info('Published total distance: %f' % self.dist_msg.data)
        

def main(args=None):
    # Initialize the ROS 2 Python client library
    rclpy.init(args=args)
    # Create an instance of the TurtleTracker node
    dist_node = TurtleTracker()
    # Spin the node to keep it active and responsive to incoming messages and timer events
    rclpy.spin(dist_node)
    # Destroy the node explicitly
    # (optional - otherwise it will be done automatically
    # when the garbage collector destroys the node object)
    dist_node.destroy_node()
    rclpy.shutdown()


if __name__ == '__main__':
    main()

🛠️ Zadanie 2.5: Uruchom turtlesim_node, otwórz drugi terminal i uruchom węzeł dist_node. W kolejnym terminalu sprawdź listę tematów i nasłuchuj tematu /travelled_distance.

🛠️ Zadanie 2.6: Uzupełnij kod w metodzie timer_callback tak aby do zmiennej self.total_distance dodawać odległość przemierzoną od ostatniej zmiany pozycji. Zapisz plik i ponownie przetestuj działanie węzła podczas sterowania żółwiem za pomocą węzła turtle_teleop_key.

🛠️ Zadanie 2.7: Nie wyłączaj węzłów z poprzedniego zadania. W nowym terminalu uruchom program rqt. Otwórz zakładkę Plugins --> Introspection --> Node Graph i sprawdź jakie węzły (nodes) i tematy (topics) są aktywne oraz jakie są między nimi połaczenia:

rqt-graph


Zadanie domowe

Jeśli nie udało Ci się wykonać wszystkich zadań podczas laboratorium, dokończ je w domu. Umiejętności z tych zajęć są konieczne podczas kolejnego laboratorium.